package com.example;

import org.junit.jupiter.api.Test;

import java.util.concurrent.*;

/**
 * 在 CompletableFuture 转换和运行
 *
 * CompletableFuture.get()方法是阻塞的。它会一直等到Future完成并且在完成后返回结果。
 * 但是，这是我们想要的吗？对于构建异步系统，我们应该附上一个回调给CompletableFuture，当Future完成的时候，自动的获取结果。
 * 如果我们不想等待结果返回，我们可以把需要等待 Future 完成执行的逻辑写入到回调函数中。
 *
 * 可以使用 thenApply(), thenAccept() 和 thenRun() 方法附上一个回调给 CompletableFuture。
 *
 */
public class Demo02Test {
    /**
     * thenApply():可以使用 thenApply() 处理和改变 CompletableFuture的结果。
     * 持有一个Function<T,R>作为参数。Function<T,R>是一个简单的函数式接口，接受一个T类型的参数，产出一个R类型的结果。
     *
     * 也可以通过附加一系列的 thenApply() 回调方法 在 CompletableFuture 写一个连续的转换。
     * 这样的话，结果中的一个 thenApply 方法就会传递给该系列的另外一个 thenApply 方法。
     */
    @Test
    public void test01() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Jack";
        }).thenApply(name -> "Hello " + name).thenApply(greeting -> greeting + ",Welcome to the Beijing");

        String result = completableFuture.get();
        System.out.println("result = " + result);
    }

    /**
     * thenAccept() 和 thenRun():如果你不想从你的回调函数中返回任何东西，仅仅想在Future完成后运行一些代码片段，
     * 你可以使用 thenAccept() 和 thenRun() 方法，这些方法经常在调用链的最末端的最后一个回调函数中使用。
     *
     * CompletableFuture.thenAccept() 持有一个 Consumer<T>，返回一个 CompletableFuture<Void>。
     * 它可以访问 CompletableFuture 的结果
     */
    @Test
    public void test02() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> "Tom")
                .thenAccept(name -> System.out.println("Hello " + name));

        completableFuture.get();
    }

    /**
     * thenRun()不能访 Future 的结果，它持有一个 Runnable 返回 CompletableFuture
     */
    @Test
    public void test03() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> "Mary")
                .thenRun(() -> System.out.println("Welcome!"));
        completableFuture.get();
    }


    @Test
    public void test04() throws ExecutionException, InterruptedException {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(50,200,5,TimeUnit.MINUTES,
                new LinkedBlockingQueue<>(1000),new ThreadPoolExecutor.CallerRunsPolicy());
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 = " + Thread.currentThread().getName());
            return "ZhangSan";
        },executor).thenApply(name -> {
            System.out.println("Thread2 = " + Thread.currentThread().getName());
            return "Hello " + name;
        });

        System.out.println("Thread3 = " + Thread.currentThread().getName());
        String result = completableFuture.get();
        System.out.println("result = " + result);
    }
}
